home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / nethack.lha / nethack-3.1 / win / X11 / winmenu.c < prev    next >
C/C++ Source or Header  |  1993-01-18  |  10KB  |  399 lines

  1. /*    SCCS Id: @(#)winmenu.c    3.1    92/3/7
  2. /* Copyright (c) Dean Luick, 1992                  */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. /*
  6.  * File for creating menus.
  7.  * 
  8.  *     + Global functions: start_menu, add_menu, end_menu, select_menu
  9.  */
  10. #include <X11/Intrinsic.h>
  11. #include <X11/StringDefs.h>
  12. #include <X11/Shell.h>
  13. #include <X11/Xaw/List.h>
  14. #include <X11/Xaw/Viewport.h>
  15. #include <X11/Xaw/Cardinals.h>
  16.  
  17. #include "hack.h"
  18. #include "winX.h"
  19.  
  20.  
  21. static void clear_old_menu();
  22. static char *copy_of();
  23.  
  24. #define check_menu(func_name)                    \
  25. {                                \
  26.     if (!menu_info->is_menu) {                    \
  27.     impossible("%s:  called before start_menu", func_name);    \
  28.     return;                            \
  29.     }                                \
  30. }
  31.  
  32. static char menu_selected;    /* selected menu item */
  33. static const char menu_translations[] =
  34.     "#override\n\
  35.      <Key>: menu_key()";
  36.  
  37. /*
  38.  * Menu callback.
  39.  */
  40. /* ARGSUSED */
  41. static void
  42. menu_select(w, client_data, call_data)
  43.     Widget w;
  44.     XtPointer client_data, call_data;
  45. {
  46.     XawListReturnStruct *lrs = (XawListReturnStruct *) call_data;
  47.     int i;
  48.     struct menu_info_t *menu_info;
  49.     struct menu_item *curr;
  50.     struct xwindow *wp;
  51.  
  52.     wp = find_widget(w);
  53.     menu_info  = wp->menu_information;
  54.  
  55.     for (i = 0, curr = menu_info->base; i < lrs->list_index; i++) {
  56.     if (!curr) panic("menu_select: out of menu items!");
  57.     curr = curr->next;
  58.     }
  59.  
  60.     /* If we don't have a selector, try again. */
  61.     if (!curr->selector) {
  62.     XawListUnhighlight(w);    /* unhilight non-menu item */
  63.     X11_nhbell();
  64.     return;
  65.     }
  66.     menu_selected = curr->selector;
  67.  
  68.     nh_XtPopdown(wp->popup);    /* this removes the event grab */
  69.     exit_x_event = TRUE;    /* exit our event handler */
  70. }
  71.  
  72. /*
  73.  * Called when we get a key press event on a menu window.
  74.  */
  75. /* ARGSUSED */
  76. void
  77. menu_key(w, event, params, num_params)
  78.     Widget w;
  79.     XEvent *event;
  80.     String *params;
  81.     Cardinal *num_params;
  82. {
  83.     struct menu_info_t *menu_info;
  84.     struct menu_item *curr;
  85.     struct xwindow *wp;
  86.     char ch;
  87.     int count;
  88.  
  89.     wp = find_widget(w);
  90.     menu_info  = wp->menu_information;
  91.  
  92.     ch = key_event_to_char((XKeyEvent *) event);
  93.  
  94.     if (ch == '\0') {    /* don't accept nul char/modifier event */
  95.     /* don't beep */
  96.     return;
  97.     }
  98.  
  99.     for (count = 0, curr = menu_info->base; curr; curr = curr->next, count++)
  100.     if (curr->selector == ch) break;
  101.  
  102.     if (curr) {
  103.     XawListHighlight(w, count);    /* highlit item */
  104.     menu_selected = ch;
  105.     } else if (menu_info->other_valid && index(menu_info->other_valid, ch)) {
  106.     menu_selected = menu_info->other_response;
  107.     } else {
  108.     X11_nhbell();        /* no match */
  109.     return;
  110.     }
  111.  
  112.     nh_XtPopdown(wp->popup);    /* this removes the event grab */
  113.     exit_x_event = TRUE;    /* exit our event handler */
  114. }
  115.  
  116.  
  117. /* Global functions ======================================================== */
  118.  
  119. void
  120. X11_start_menu(window)
  121.     winid window;
  122. {
  123.     struct xwindow *wp;
  124.     check_winid(window);
  125.  
  126.     wp = &window_list[window];
  127.  
  128.     if (wp->menu_information->is_menu) {
  129.     /* clear old menu and widgets (if any) */
  130.     clear_old_menu(wp);
  131.     } else {
  132.     wp->menu_information->is_menu = TRUE;
  133.     }
  134. }
  135.  
  136. void
  137. X11_add_menu(window, ch, attr, str)
  138.     winid window;
  139.     char ch;
  140.     int attr;
  141.     const char *str;
  142. {
  143.     struct menu_item *item;
  144.     struct menu_info_t *menu_info;
  145.  
  146.     check_winid(window);
  147.     menu_info = window_list[window].menu_information;
  148.     check_menu("add_menu");
  149.  
  150.     item = (struct menu_item *) alloc((unsigned)sizeof(struct menu_item));
  151.     item->next = (struct menu_item *) 0;
  152.     item->selector = ch;
  153.     item->attr = attr;
  154.     item->str = copy_of(str);
  155.  
  156.     if (menu_info->last) {
  157.     menu_info->last->next = item;
  158.     } else {
  159.     menu_info->base = item;
  160.     }
  161.     menu_info->last = item;
  162.     menu_info->count++;
  163. }
  164.  
  165. void
  166. X11_end_menu(window, cancel_ch, cancel_str, morestr)
  167.     winid window;
  168.     char cancel_ch;
  169.     const char *cancel_str;
  170.     const char *morestr;
  171. {
  172.     struct menu_info_t *menu_info;
  173.     check_winid(window);
  174.     menu_info = window_list[window].menu_information;
  175.     check_menu("end_menu");
  176.  
  177.     if(morestr && strlen(morestr))
  178.     X11_add_menu(window, 0, 0, morestr);
  179.     menu_info->other_valid = cancel_str;
  180.     menu_info->other_response = cancel_ch;
  181.     menu_info->query = morestr;
  182. }
  183.  
  184. char
  185. X11_select_menu(window)
  186.     winid window;
  187. {
  188.     struct menu_item *curr;
  189.     struct xwindow *wp;
  190.     struct menu_info_t *menu_info;
  191.     Arg args[8];
  192.     Cardinal num_args;
  193.     String *ptr;
  194.     int i;
  195.     Widget viewport_widget;
  196.     Dimension pixel_height, top_margin, spacing;
  197.     XFontStruct *fs;
  198.  
  199.     check_winid(window);
  200.     wp = &window_list[window];
  201.     menu_info = wp->menu_information;
  202.  
  203. #if defined(LINT) || defined(GCC_WARN)
  204.     {
  205.     /* cannot use check_menu, since it doesn't return anything */
  206.     if (!menu_info->is_menu) {
  207.         impossible("%s:  called before start_menu", "select_menu");
  208.         return '\0';
  209.     }
  210.     }
  211. #else
  212.     check_menu("select_menu");
  213. #endif
  214.  
  215. #ifdef VERBOSE
  216.     /* ********** */
  217.     if (menu_info->other_valid) {
  218.     char *cp;
  219.     printf("select_menu: other_valid = \"");
  220.     for (cp = menu_info->other_valid; *cp; cp++) {
  221.         if (*cp < 32) {
  222.         printf("^%c", '@' + *cp);
  223.         } else
  224.         printf("%c", *cp);
  225.     }
  226.     printf("\"\n");
  227.     } else {
  228.     printf("select_menu: other_valid = NULL\n");
  229.     }
  230.     if (menu_info->other_response < 32) {
  231.     printf("select_menu: other_response = '^%c'\n",
  232.                     '@' + menu_info->other_response);
  233.     } else {
  234.     printf("select_menu: other_response = '%c'\n",
  235.                         menu_info->other_response);
  236.     }
  237.     if (menu_info->query) {
  238.     printf("select_menu: query = \"%s\"\n", menu_info->query);
  239.     } else {
  240.     printf("select_menu: query = NULL\n");
  241.     }
  242.     /* ********** */
  243. #endif
  244.  
  245.     num_args = 0;
  246.     XtSetArg(args[num_args], XtNallowShellResize, True); num_args++;
  247.  
  248.     wp->popup = XtCreatePopupShell("menu", transientShellWidgetClass,
  249.                    toplevel, args, num_args);
  250.  
  251.     menu_info->list_pointer =
  252.     (String *) alloc((unsigned) (sizeof(String) * (menu_info->count+1)));
  253.     for (i = 0, ptr = menu_info->list_pointer, curr = menu_info->base;
  254.             i < menu_info->count; i++, ptr++, curr = curr->next) {
  255.     *ptr = (String) curr->str;
  256.     }
  257.     *ptr = (String) 0;
  258.  
  259.     num_args = 0;
  260.     XtSetArg(args[num_args], XtNallowVert,      True);           num_args++;
  261.  
  262.     viewport_widget = XtCreateManagedWidget(
  263.         "menu_viewport",    /* name */
  264.         viewportWidgetClass,
  265.         wp->popup,        /* parent widget */
  266.         args, num_args);    /* values, and number of values */
  267.  
  268.     num_args = 0;
  269.     XtSetArg(args[num_args], XtNforceColumns, True);        num_args++;
  270.     XtSetArg(args[num_args], XtNdefaultColumns, 1);        num_args++;
  271.     XtSetArg(args[num_args], XtNlist, menu_info->list_pointer);    num_args++;
  272.     XtSetArg(args[num_args], XtNtranslations,
  273.         XtParseTranslationTable(menu_translations));    num_args++;
  274.  
  275.     wp->w = XtCreateManagedWidget(
  276.         "menu_list",        /* name */
  277.         listWidgetClass,
  278.         viewport_widget,    /* parent widget */
  279.         args,            /* set some values */
  280.         num_args);        /* number of values to set */
  281.  
  282.     XtAddCallback(wp->w, XtNcallback, menu_select, (XtPointer) 0);
  283.  
  284.     menu_info->valid_widgets = TRUE;
  285.  
  286.     /* Get the font and margin information. */
  287.     num_args = 0;
  288.     XtSetArg(args[num_args], XtNfont,          &fs);         num_args++;
  289.     XtSetArg(args[num_args], XtNinternalHeight, &top_margin);    num_args++;
  290.     XtSetArg(args[num_args], XtNrowSpacing,     &spacing);    num_args++;
  291.     XtGetValues(wp->w, args, num_args);
  292.  
  293.     /* font height is ascent + descent */
  294.     pixel_height = top_margin +
  295.     ((menu_info->count + 4) *
  296.      (fs->max_bounds.ascent + fs->max_bounds.descent + spacing));
  297.  
  298.     /* if viewport will be bigger than the screen, limit its height */
  299.     if ((Dimension) XtScreen(wp->w)->height <= pixel_height) {
  300.     pixel_height = XtScreen(wp->w)->height / 2;
  301.  
  302.     num_args = 0;
  303.     XtSetArg(args[num_args], XtNheight, pixel_height); num_args++;
  304.     XtSetValues(viewport_widget, args, num_args);
  305.     }
  306.  
  307.     XtRealizeWidget(wp->popup);    /* need to realize before we position */
  308.     positionpopup(wp->popup);
  309.  
  310.     menu_selected = '\0';
  311.  
  312.     nh_XtPopup(wp->popup, XtGrabExclusive, wp->w);
  313.     (void) x_event(EXIT_ON_EXIT);
  314.  
  315.     return menu_selected;
  316. }
  317.  
  318. /* End global functions ==================================================== */
  319.  
  320. static char *
  321. copy_of(s)
  322.     char *s;
  323. {
  324.     char *copy;
  325.     if (s) {
  326.     copy = (char *) alloc((unsigned) (strlen(s)+1));
  327.     Strcpy(copy,s);
  328.     } else {
  329.     copy = (char *) alloc((unsigned) 1);
  330.     *copy = '\0';
  331.     }
  332.  
  333.     return copy;
  334. }
  335.  
  336. static void
  337. clear_old_menu(wp)
  338.     struct xwindow *wp;
  339. {
  340.     struct menu_info_t *menu_info = wp->menu_information;
  341.  
  342.     while (menu_info->base) {
  343.     menu_info->last = menu_info->base;
  344.     menu_info->base = menu_info->base->next;
  345.  
  346.     free(menu_info->last->str);
  347.     free((char *)menu_info->last);
  348.     }
  349.     menu_info->last = (struct menu_item *) 0;
  350.     menu_info->other_valid = (char *) 0;
  351.     menu_info->other_response = '\0';
  352.     menu_info->query = (char *) 0;
  353.     menu_info->count = 0;
  354.  
  355.     if (menu_info->valid_widgets) {
  356.     nh_XtPopdown(wp->popup);
  357.     XtDestroyWidget(wp->popup);
  358.     menu_info->valid_widgets = FALSE;
  359.     free((char *) menu_info->list_pointer);
  360.     }
  361. }
  362.  
  363. void
  364. create_menu_window(wp)
  365.     struct xwindow *wp;
  366. {
  367.     struct menu_info_t *menu_info;
  368.  
  369.     wp->type = NHW_MENU;
  370.  
  371.     wp->menu_information = menu_info = 
  372.             (struct menu_info_t *) alloc(sizeof(struct menu_info_t));
  373.  
  374.     menu_info->base          = (struct menu_item *) 0;
  375.     menu_info->last          = (struct menu_item *) 0;
  376.     menu_info->query          = (char *) 0;
  377.     menu_info->other_valid    = (char *) 0;
  378.     menu_info->other_response = '\0';
  379.     menu_info->count          = 0;
  380.     menu_info->list_pointer   = (String *) 0;
  381.     menu_info->valid_widgets  = FALSE;
  382.     wp->w = wp->popup = (Widget) 0;
  383.     menu_info->is_menu          = FALSE;
  384. }
  385.  
  386. void
  387. destroy_menu_window(wp)
  388.     struct xwindow *wp;
  389. {
  390.     /* printf("destroy_menu_window\n"); */
  391.  
  392.     clear_old_menu(wp);        /* this will also destroy the widgets */
  393.     free((char *) wp->menu_information);
  394.  
  395.     wp->type = NHW_NONE;    /* allow re-use */
  396. }
  397.  
  398.  
  399.